package com.ls.fw.mvc.springmvc.support.interceptor;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.ModelAndView;

import com.ls.fw.commons.core.utils.collections.CollectionUtils;
import com.ls.fw.web.core.servlet.utils.HttpUtils;
import com.ls.fw.web.core.support.matcher.IpAddressMatcher;
import com.ls.fw.web.core.support.matcher.RequestMatcher;


/**
 * 访问拦截器：
 * deny优先于allow，如果在deny列表中，就算在allow列表中，也会被拒绝。
	        如果allow没有配置或者为空，则允许所有访问
	配置的格式
		  IP
		  或者
		  IP/SUB_NET_MASK_size
		其中
		  128.242.127.1/24
		24表示，前面24位是子网掩码，比对的时候，前面24位相同就匹配。
		如：128.242.127.1/24,128.242.128.1
 * @author lisheng
 * @date 2016年1月22日 下午8:27:52
 * @version V1.0
 */
public class AccessControllerInterceptor extends BaseInterceptor implements InitializingBean{

	public static final String PARAM_NAME_ALLOW = "allow";
	public static final String PARAM_NAME_DENY = "deny";
	// no need to inject it for now..
    private PathMatcher pathMatcher = new AntPathMatcher();

	/**
	 * 不包含的连接
	 */
	protected List<String> excludedUrl = null;

	/**
	 * 包含的连接
	 */
	protected List<String> includedUrl = null;
	/**
	 * 允许访问的地址
	 */
	protected String allow = "";

	/**
	 * 不允许访问的地址
	 */
	protected String deny = "";
    
    private List<RequestMatcher> allowList = new ArrayList<RequestMatcher>();
    private List<RequestMatcher> denyList = new ArrayList<RequestMatcher>();
    


	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception) throws Exception {
		
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView) throws Exception {
			
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		 boolean ret = true; 
		 if (open) {
			 ret = false;
			 if (this.isPermittedRequest(request)) {
				 String path = request.getRequestURI();
				 if(this.isInValidUrl(path)){
					 ret = false;
					 logger.info("--deny url:" + path);
				 }else{
					 if(this.isValidUrl(path)){
						 ret = true;
					 }else{
						logger.info("--deny url:" + path);
					 }
				 }
			 }else{
				 logger.info("--deny ip:" + HttpUtils.getIp(request));
				 ret = false;
			 }
		 }
		return ret;
	}


	/**
	 * 是否为允许的连接
	 * 
	 * @author lisheng
	 * @date 2016年1月22日 下午8:14:31
	 * @version V1.0
	 * @param path
	 * @return
	 */
	protected boolean isValidUrl(String path) {
		if(CollectionUtils.isEmpty(includedUrl)){
			return true;
		}
		return this.isValid(this.includedUrl, path);
	}

	protected boolean isValid(List<String> list, String path) {
    	boolean flag = false;
		if(list != null){
	        for (String pattern : list) {
	            if (pathMatcher.match(pattern, path)) {
	            	flag = true;
	            	break;
	            }
	        }
	    }
        return flag;
    }
	
	/**
	 * 是否为无效的连接
	 * 
	 * @author lisheng
	 * @date 2016年1月22日 下午8:15:00
	 * @version V1.0
	 * @param path
	 * @return
	 */
	protected boolean isInValidUrl(String path) {
		return this.isValid(excludedUrl, path);
	}
	
	/**
	 * 
	 * @author lisheng
	 * @date 2016年3月11日 下午8:45:40
	 * @version V1.0
	 * @param request
	 * @return
	 */
	private boolean isPermittedRequest(HttpServletRequest request) {
		boolean ok = false;
		ok = isExist(denyList, request, false);
		if(!ok){
			ok = isExist(allowList, request, true);
		}
		return ok;
	}
 

	private void setAddrs(List<RequestMatcher> list,String addrs) {
		if (addrs.indexOf(',') > 0) {
			String[] addressAndMasks = StringUtils.split(addrs, ",");
			if(addressAndMasks!=null){
				for (String string : addressAndMasks) {
				    RequestMatcher matcher = new IpAddressMatcher(string);
				    list.add(matcher);
				}
			}
		}
	}
	
	private boolean isExist(List<RequestMatcher> list,HttpServletRequest request ,boolean valueIfExist){
		boolean ok = valueIfExist;
		if(list!=null && !list.isEmpty()){
			for (RequestMatcher matcher : allowList) {
				if(matcher.matches(request)){
					ok = true;
					break;
				}
			}
		}
		return ok;
	}

	public List<String> getExcludedUrl() {
		return this.excludedUrl;
	}

	public void setExcludedUrl(List<String> excludedUrl) {
		this.excludedUrl = excludedUrl;
	}

	public List<String> getIncludedUrl() {
		return this.includedUrl;
	}

	public void setIncludedUrl(List<String> includedUrl) {
		this.includedUrl = includedUrl;
	}

	public String getAllow() {
		return this.allow;
	}

	public void setAllow(String allow) {
		this.allow = allow;
	}

	public String getDeny() {
		return this.deny;
	}

	public void setDeny(String deny) {
		this.deny = deny;
	}

	public List<RequestMatcher> getAllowList() {
		return this.allowList;
	}

	public void setAllowList(List<RequestMatcher> allowList) {
		this.allowList = allowList;
	}

	public List<RequestMatcher> getDenyList() {
		return this.denyList;
	}

	public void setDenyList(List<RequestMatcher> denyList) {
		this.denyList = denyList;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		this.setAddrs(this.allowList, this.allow);
		this.setAddrs(this.denyList, this.deny);
	}
	
}
